
include( "framebuffer.lua" )
include( "cl_text_capture.lua" )
include( "shared.lua" )
include( "cl_render.lua" )

require "textcapture"

local function char_array( str )
	local bigstr = ""
	for w in str:gmatch( "[^ ]+" ) do
		bigstr = bigstr .. string.char( w )
	end
	return bigstr
end

local str_blk_wmn = [[226 149 148 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 32 224 179 139 225 131 166 225 131 166 224 179 139 32 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 151 10 126 32 126 32 126 32 126 32 126 32 126 32 126 32 126 32 126 32 126 32 82 101 112 111 115 116 32 116 104 105 115 32 105 102 32 126 32 126 32 126 32 126 32 126 32 126 32 126 32 126 32 10 126 32 126 32 126 32 126 32 121 111 117 32 97 114 101 32 97 32 98 101 97 117 116 105 102 117 108 32 115 116 114 111 110 103 32 98 108 97 99 107 32 119 111 109 97 110 32 126 32 126 32 10 126 32 126 32 126 32 126 32 126 32 126 32 119 104 111 32 100 111 110 39 116 32 110 101 101 100 32 110 111 32 109 97 110 32 126 32 126 32 126 32 126 32 126 32 126 32 126 10 226 149 154 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 32 224 179 139 225 131 166 225 131 166 224 179 139 32 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 144 226 149 157]]

GM.Description = [[Initial G is a racing/RTS gamemode.

 * Goal: Try to finish first.
 * Twist: Shoot manhacks to get money, and use money to build
    blockades and turrets.
	
Scripted by Henry Tran ( Hen Tie )

]] .. char_array( str_blk_wmn )


GM.Chat = "Press enter to chat."
GM.LastCash = 0
	
function GM:InitPostEntity()

	GAMEMODE:LoadBlocks()
	
end

function GM:Initialize()
	surface.CreateFont( "coolvetica", 38, 400, true, false, "TimeFontSmall" )
	surface.CreateFont( "coolvetica", 48, 400, true, false, "TimeFont" )
end
	
function GM:PostGamemodeLoaded()

	GAMEMODE:LoadVGUI()

end

function GM:LoadVGUI()

	textcapture.Init()

	if g_WaitingPanel then
		g_WaitingPanel:Remove()
	end

	g_WaitingPanel = vgui.Create( "DFrame" )
	g_WaitingPanel:SetTitle( "Initial G - Lobby" )
	g_WaitingPanel:SetDraggable( false )
	g_WaitingPanel:SetBackgroundBlur( true )
	g_WaitingPanel:SetDeleteOnClose( false )
	g_WaitingPanel:SetSize( 540,440 )
	g_WaitingPanel:SetMouseInputEnabled( true )
	g_WaitingPanel:SetKeyboardInputEnabled( true )
	g_WaitingPanel:ShowCloseButton( false )
	g_WaitingPanel:Center()
	
	pDescriptionWrapper = vgui.Create( "DPanelList", g_WaitingPanel )
	pDescriptionWrapper:EnableVerticalScrollbar( true )
	pDescriptionWrapper:SetPos( 5, 28 )
	pDescriptionWrapper:SetSize( 320, 210 )
	pDescriptionWrapper:SetPadding( 5 )
	pDescriptionWrapper:SetSpacing( 5 )
	
	pDescriptionBox = vgui.Create( "DLabel" )
	pDescriptionBox:SetAutoStretchVertical( true )
	pDescriptionBox:SetText( GAMEMODE.Description )
	pDescriptionBox:SetWrap( true )
	pDescriptionBox:SetPos( 0, 0 )
	pDescriptionBox:SetWide( 300 )
	pDescriptionWrapper:AddItem( pDescriptionBox )
	
	g_ChatWrapper = vgui.Create( "DPanelList", g_WaitingPanel )
	g_ChatWrapper:EnableVerticalScrollbar( true )
	g_ChatWrapper:SetPos( 5, 248 )
	g_ChatWrapper:SetSize( 320, 160 )
	g_ChatWrapper:SetPadding( 5 )
	g_ChatWrapper:SetSpacing( 5 )
	g_ChatWrapper:SetFGColor( color_black )
	g_ChatWrapper.Paint = function( self )
		surface.SetDrawColor( color_black )
		surface.DrawRect( 0, 0, self:GetWide(), self:GetTall(), color_black )
	end
	
	g_ChatBox = vgui.Create( "DLabel" )
	g_ChatBox:SetAutoStretchVertical( true )
	g_ChatBox:SetText( GAMEMODE.Chat )
	g_ChatBox:SetWrap( true )
	g_ChatBox:SetPos( 0, 0 )
	g_ChatWrapper:AddItem( g_ChatBox )
	
	g_ChatEntry = vgui.Create( "DTextEntry", g_WaitingPanel )
	g_ChatEntry:SetEditable( true )
	g_ChatEntry:SetPos( 5, 413 )
	g_ChatEntry:SetWide( 320 )
	g_ChatEntry:SetKeyboardInputEnabled( true )
	g_ChatEntry:SetMouseInputEnabled( true )
	g_ChatEntry:MouseCapture()
	g_ChatEntry:RequestFocus()
	g_ChatEntry.CarotPos = 0
	g_ChatEntry.OnKeyCodeTyped = function( self, value )
		local cur_text = g_ChatEntry:GetValue()
		if value == KEY_BACKSPACE then
			g_ChatEntry:SetText(string.sub( cur_text, 1, g_ChatEntry.CarotPos-1 ) .. string.sub( cur_text, g_ChatEntry.CarotPos+1, -1 ))
			g_ChatEntry.CarotPos = g_ChatEntry.CarotPos - 1
		elseif value == KEY_LEFT then
			g_ChatEntry.CarotPos = g_ChatEntry.CarotPos - 1
		elseif value == KEY_RIGHT then
			g_ChatEntry.CarotPos = g_ChatEntry.CarotPos + 1
		elseif value == KEY_ENTER then
			RunConsoleCommand( "say", g_ChatEntry:GetValue() )
			g_ChatEntry:SetText( "" )
		end
		if g_ChatEntry.CarotPos > string.len( g_ChatEntry:GetValue() ) then
			g_ChatEntry.CarotPos = string.len( g_ChatEntry:GetValue() )
		end
		if g_ChatEntry.CarotPos < 0 then
			g_ChatEntry.CarotPos = 0
		end
	end
	g_ChatEntry.OnTextEntry = function( self, value )
		if value == "`" then return end
		local cur_text = g_ChatEntry:GetValue()
		g_ChatEntry:SetText(string.sub( cur_text, 1, g_ChatEntry.CarotPos ) .. value .. string.sub( cur_text, g_ChatEntry.CarotPos+1, -1 ))
		g_ChatEntry.CarotPos = g_ChatEntry.CarotPos + string.len( value )
	end
	g_ChatEntry.PaintOver = function()
		surface.SetFont( "default" )
		local w,h = surface.GetTextSize( string.sub( g_ChatEntry:GetValue(), 1, g_ChatEntry.CarotPos ) )
		surface.SetDrawColor( color_black )
		surface.DrawRect( w+3,2,1,16 )
	end
	
	g_WaitingList = vgui.Create( "DPanelList", g_WaitingPanel )
	g_WaitingList:EnableVerticalScrollbar( true )
	g_WaitingList:SetPos( 334, 28 )
	g_WaitingList:SetSize( 200, 360 )
	g_WaitingList:SetPadding( 5 )
	g_WaitingList:SetSpacing( 5 )
	
	g_WaitingTable = {}
	
	for _,pl in pairs( player.GetAll() ) do
		GAMEMODE:AddPlayerPanel( pl )
	end
	
	pReadyButton = vgui.Create( "DButton", g_WaitingPanel )
	pReadyButton:SetText( "READY" )
	pReadyButton:SetPos( 334, 393 )
	pReadyButton:SetSize( 200, 40 )
	pReadyButton.Ready = false
	pReadyButton.DoClick = function ( self )
		if self.Ready then
			self.Ready = false
			self:SetText( "READY" )
			RunConsoleCommand( "unready" )
		else
			self.Ready = true
			self:SetText( "UNREADY" )
			RunConsoleCommand( "ready" )
		end
	end
	
	if g_SpawnPanel then
		g_SpawnPanel:Remove()
	end
	
	g_SpawnPanel = vgui.Create( "DPanelList" )
	g_SpawnPanel:SetSize( rScrScale(230), rScrScale(50) )
	g_SpawnPanel:SetSpacing( rScrScale(5) )
	g_SpawnPanel:SetPadding( rScrScale(5) )
	g_SpawnPanel:EnableHorizontal( true )
	g_SpawnPanel:SetPos( ScrW()/2 - g_SpawnPanel:GetWide()/2, ScrH()-g_SpawnPanel:GetTall() )
	
end

syncvar.SetCallback( "waiting", function( is_waiting )
	if is_waiting then
		g_WaitingPanel:SetVisible( true )
		g_SpawnPanel:SetVisible( false )
		textcapture.Set( g_ChatEntry )
		vgui.GetWorldPanel():SetCursor( "none" )
		GAMEMODE.Chat = "Press enter to chat."
	else
		g_WaitingPanel:SetVisible( false )
		g_SpawnPanel:SetVisible( true )
		textcapture.Set( )
		vgui.GetWorldPanel():SetCursor( "blank" )
	end
end )

syncvar.SetCallbackEntity( "ready", function( pl, isready )
	if not ValidEntity( pl ) then return end
	if not g_WaitingTable[ pl ] then return end
	
	if isready then
		g_WaitingTable[ pl ].StatusPanel:SetImage( "gui/silkicons/check_on" )
	else
		g_WaitingTable[ pl ].StatusPanel:SetImage( "gui/silkicons/check_off" )
	end
end )

function GM:OnPlayerChat( pl, str, teamchat, dead )
	GAMEMODE.Chat = GAMEMODE.Chat .. "\n" .. pl:Nick() .. ": " .. str
	
	g_ChatBox:SetText( GAMEMODE.Chat )
	g_ChatBox:InvalidateLayout()
	g_ChatWrapper:InvalidateLayout()
	g_ChatWrapper:Rebuild()
	g_ChatWrapper:PerformLayout()
	g_ChatWrapper.VBar:InvalidateLayout()
	g_ChatWrapper.VBar:PerformLayout()
	g_ChatWrapper.VBar:SetScroll( g_ChatBox:GetTall() )
end

function GM:AddPlayerPanel( pl )
	local waiting_panel = vgui.Create( "DPanel" )
	waiting_panel:SetSize( 190, 42 )
	
	local av = vgui.Create( "AvatarImage", waiting_panel )
	av:SetPos(5,5)
	av:SetSize(32, 32)
	av:SetPlayer( pl, 32 )
	
	local label = vgui.Create( "DLabel", waiting_panel )
	label:SetText( pl:Nick() )
	label:SetPos( 42, 5 )
	label:SetSize( 143, 10 )
	
	local status = vgui.Create( "DImage", waiting_panel )
	status:SetImage( "gui/silkicons/check_off" )
	status:SetPos( 42, 19 )
	status:SetSize( 16, 16 )
	
	waiting_panel.Name = label
	waiting_panel.StatusPanel = status
	
	g_WaitingTable[ pl ] = waiting_panel
	g_WaitingList:AddItem( waiting_panel )
end

function GM:PlayerAuthed( pl, steamid, uniqueid )
	GAMEMODE:AddPlayerPanel( pl )
end

GM.to_auth = {}
function GM:PlayerConnected( pl )
	table.insert( GAMEMODE.to_auth, pl )
end

function GM:PlayerDisconnected( pl )
	if g_WaitingTable[ pl ] then
		g_WaitingList:RemoveItem( g_WaitingTable[ pl ] )
	end

	g_WaitingList:InvalidateLayout()
	g_WaitingList:Rebuild()
end

function GM:PlayerSpawn( pl )

	GAMEMODE:Buggify( pl )

end

function GM:PlayerBindPress( ply, bind, pressed )
	-- No flashlight for you!
	if( string.find( bind, "impulse 100" ) ) then return true end
end 



-- TODO: Add more bindings.
local binding_to_in = {
[IN_ATTACK] = "+attack",
[IN_ATTACK2] = "+attack2"
}
local binding_is_mouse = {
MOUSE1 = MOUSE_LEFT,
MOUSE2 = MOUSE_RIGHT,
MOUSE3 = MOUSE_MIDDLE,
MOUSE4 = MOUSE_4,
MOUSE5 = MOUSE_5,
MWHEELUP = MOUSE_WHEEL_UP,
MWHEELDOWN = MOUSE_WHEEL_DOWN
}
function GM:IsInKeyDown( key )
	local cmd = LocalPlayer():GetCurrentCommand()
	if( cmd:KeyDown( key ) ) then
		return true
	else
		if ( binding_to_in[key] ) then
			local is_mouse = input.LookupBinding( binding_to_in[key] )
			if binding_is_mouse[is_mouse] then
				return input.IsMouseDown( binding_is_mouse[is_mouse] )
			end
		end
	end
end

function GM:KeyPress(pl,key)
end


function GM:OverSpawnMenu()
	local mx, my = gui.MousePos()
	local x, y = g_SpawnPanel:GetPos()
	local w, h = g_SpawnPanel:GetSize()
	return ( mx > x and my > y and mx < x + w and my < y + h )
end

function GM:KeyPress( pl, key )
end

function GM:KeyRelease( pl, key )
end

local lastAttackDown = false
local lastAttack2Down = false
local lastScrW, lastScrH = ScrW(), ScrH()
function GM:Think()
	if lastScrW != ScrW() or lastScrH != ScrH() then
		GAMEMODE:ScreenSizeChanged( ScrW(), ScrH() )
	end
	lastScrW, lastScrH = ScrW(), ScrH()

	local attack2Down = GAMEMODE:IsInKeyDown( IN_ATTACK2 )
	if GAMEMODE:IsCreatingBlock() and attack2Down and not lastAttack2Down then
		GAMEMODE:CancelBlockCreation()
	end
	lastAttack2Down = attack2Down
	
	local attackDown = GAMEMODE:IsInKeyDown( IN_ATTACK )
	local canAttack = attackDown and not ( GAMEMODE:OverSpawnMenu() or GAMEMODE:IsCreatingBlock() )
	if !lastAttackDown and canAttack then
		RunConsoleCommand( "+attack3", LocalPlayer():GetSyncVar( "optimism" ) )
	elseif lastAttackDown and !canAttack then
		RunConsoleCommand( "-attack3", LocalPlayer():GetSyncVar( "optimism" ) )
	elseif lastAttackDown and canAttack and ValidEntity(to_aim_at) then
		RunConsoleCommand( "+attack3", LocalPlayer():GetSyncVar( "optimism" ) )
	end
	if ValidEntity(to_aim_at) and canAttack then
		RunConsoleCommand( "+attack3", to_aim_at:EntIndex(), LocalPlayer():GetSyncVar( "optimism" ) )
	end
	
	local pl = LocalPlayer()
	
	if ( pl:GetWeapon() ) then
		local aimVec = pl:GetWeapon():GetAimVector()
		RunConsoleCommand( "update_aim_angle", aimVec.x, aimVec.y, aimVec.z, LocalPlayer():GetSyncVar( "optimism" ) )
	end
	
	local check_automatic = pl:GetWeapon() and ( pl:GetWeapon().Automatic or ( not pl:GetWeapon().Automatic and not lastAttackDown ) )
	
	if check_automatic and canAttack and pl:GetWeapon():CanAttack() and pl.Buggy then
		pl:GetWeapon():PrimaryAttack( to_aim_at )
	end
	if GAMEMODE:IsCreatingBlock() and attackDown and not lastAttackDown and not GAMEMODE:OverSpawnMenu() then
		GAMEMODE:CreateBlock()
	end
	lastAttackDown = attackDown
	
	if pl:GetWeapon() then
		pl:GetWeapon():FindTarget()
		pl:GetWeapon():Think()
	end

	for _,rag in pairs( ents.FindByClass( "class C_ClientRagdoll" ) ) do
		rag.AliveTime = rag.AliveTime or 10
		rag.AliveTime = rag.AliveTime - FrameTime()*10
		rag:SetColor( 255, 255, 255, (10-rag.AliveTime)*255 )
		if rag.AliveTime < 0 then
			rag:Remove()
		end
	end
	local i = 1
	while ( GAMEMODE.to_auth[i] ) do
		local pl = GAMEMODE.to_auth[i]
		if pl:Nick() != "unconnected" and pl:SteamID() and pl:SteamID() != "STEAM_ID_PENDING" and pl:UniqueID() and pl:EntIndex() then
			GAMEMODE:PlayerAuthed( pl, pl:SteamID(), pl:UniqueID() )
			table.remove( GAMEMODE.to_auth, i )
		else
			i = i + 1
		end
	end
end

local towait = {}
function GM:OnEntityCreated( ent )
	if ent:IsPlayer() then
		if towait[ent:EntIndex()] then
			towait[ent:EntIndex()] = nil
			GAMEMODE:PlayerSpawn( ent )
		end
		GAMEMODE:PlayerConnected( ent )
	end
end

function GM:EntityRemoved( ent )
	if ent:IsPlayer() then
		GAMEMODE:PlayerDisconnected( ent )
	end
end

function GM:ShouldDrawLocalPlayer()
	return true
end

usermessage.Hook( "player_spawn", function( um )
	local id = um:ReadShort()
	local ent = ents.GetByIndex(id)
	if not ValidEntity( ent ) then towait[id] = true return end
	GAMEMODE:PlayerSpawn( ent )
end)

usermessage.Hook( "update_checkpoint", function( um )
	pos_about_nothing = um:ReadVector()
	pos_about_checkpoint = um:ReadShort()
end)